package com.idroc.endpoint.impl;

import java.net.InetSocketAddress;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.idroc.endpoint.Endpoint;
import com.idroc.endpoint.EndpointChangeListner;
import com.idroc.rpc.RPCFactory;
import com.idroc.rpc.RPCService;

/**
 * 代理注册端点
 * @author 赤脚詹(yuyoo4j@163.com)
 * @date Aug 17, 2009 4:48:08 PM 
 * @memo:
 */
@SuppressWarnings("serial")
public class ProxyEndpoint implements Endpoint {
	
	private static final Logger log = LoggerFactory.getLogger(ProxyEndpoint.class);
	
	/**
	 * 远程端点编号
	 */
	private Integer remoteNo = null;
	
	/**
	 * 远程端点主机(IP or domain name)
	 */
	private String remoteHost = null;
	
	/**
	 * 远程端点端口
	 */
	private Integer remotePort = null; 
	
	/**
	 * hashcode
	 */
	private transient int hashCode = 0;
	
	/**
	 * 远程端点代理
	 */
	private transient Endpoint remote = null;
	
	private transient RPCService rpcService = null;
	
	public ProxyEndpoint() {}
	
	public ProxyEndpoint(String host, Integer port) {
		
		this.remoteHost = host;
		this.remotePort = port; 
		this.remote = getRemote();
	}
	
	public ProxyEndpoint(Endpoint ep) {
		this(ep.getEndpointHost(), ep.getEndpointPort()); 
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#addEndpoint(com.idroc.endpoint.Endpoint, com.idroc.endpoint.Endpoint)
	 */
	public boolean addEndpoint(Endpoint master, Endpoint newSlave) { 
		
		try {
			log.debug("命令 端点[{}]增加一个端点[{}]", this, newSlave);
			log.debug("命令来自主端点[{}]", master); 
			return getRemote().addEndpoint(master, newSlave);
		} catch (Exception ex) {
			log.error("命令远程端点增加一个端点异常", ex);
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#checkAlive()
	 */
	public boolean checkAlive() { 
		
		try {  
			boolean rtv =  getRemote().checkAlive();
			log.debug("检测端点[{}]是否存活:{}", this, rtv);
			return rtv;
		} catch (Exception ex) {
			log.error("端点[{}]处于异常状态", this);
			log.error("检测端点存活异常", ex);
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#dropEndpoint(com.idroc.endpoint.Endpoint, java.lang.Integer)
	 */
	public boolean dropEndpoint(Endpoint master, Integer epNo) {

		try { 
			log.debug("移除端点. master:{}, epNo:{}", master, epNo);
			return getRemote().dropEndpoint(master, epNo);
		} catch (Exception ex) { 
			log.error("移除端点异常", ex);
		}
		return false;
	}

	public String getEndpointHost() {
		
		return remoteHost;
	}

	public Integer getEndpointNo() {

		return remoteNo;
	}

	public Integer getEndpointPort() {

		return remotePort;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#getMasterEndpoint()
	 */
	public Endpoint getMasterEndpoint() {
		
		try { 
			log.debug("通过端点[{}]获取主端点", this);
			return getRemote().getMasterEndpoint();
		} catch (Exception ex) { 
			log.error("获取主端点异常", ex);
		}
		return null;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#getSlaveEndpoint()
	 */
	public TreeMap<Integer, Endpoint> getSlaveEndpoint() { 
		
		try { 
			log.debug("通过端点[{}]获取全部从端点集合", this);
			return getRemote().getSlaveEndpoint();
		} catch (Exception ex) {
			log.error("获取从端点异常", ex);
		}
		return null;
	}

	public boolean isMasterEndpoint() {
		
		try { 
			boolean isMaster =  getRemote().isMasterEndpoint();
			log.debug("检测端点[{}]是否是主端点. isMaster:{}", this, isMaster);
			return isMaster;
		} catch (Exception ex) {
			log.error("检测端点是否是主端点异常", ex);
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#rebuildMasterEndpoint(boolean)
	 */
	public Endpoint rebuildMasterEndpoint(boolean nested) {
		try { 
			log.debug("通过端点[{}]重建主端点. nested:{}", this, nested);
			return getRemote().rebuildMasterEndpoint(nested);
		} catch (Exception ex) {
			log.error("重建主端点异常", ex);
		}
		return null;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#registerEndpoint(com.idroc.endpoint.Endpoint)
	 */
	public boolean registerEndpoint(Endpoint ep) {
		try { 
			log.debug("通过端点[{}]注册一个端点[{}]", this, ep);
			return getRemote().registerEndpoint(ep);
		} catch (Exception ex) {
			log.error("注册端点异常", ex);
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#replaceMasterEndpoint(com.idroc.endpoint.Endpoint)
	 */
	public boolean replaceMasterEndpoint(Endpoint ep) {
		try { 
			log.debug("命令端点[{}]使用最新的主端点替换旧的主端点[{}]", this, ep);
			return getRemote().replaceMasterEndpoint(ep);
		} catch (Exception ex) {
			log.error("最新的主端点替换旧的主端点异常", ex);
		}
		return false;
	}

	public boolean unregisterEndpoint(Integer epNo) {
		try { 
			log.debug("通过端点[{}]移除一个端点[{}]", this, epNo);
			return getRemote().unregisterEndpoint(epNo);
		} catch (Exception ex) {
			log.error("移除端点异常", ex);
		}
		return false;
	}  


	
	/**
	 * 当 编号相同, 主机IP相同, 端口相同, 认为两个端点相同
	 */
	@Override
	public boolean equals(Object obj) { 
		
		if (null == obj) {
			return false;
		}
		if (obj instanceof Endpoint) {
			Endpoint ep = (Endpoint)obj;
			Integer no = ep.getEndpointNo();
			String host = ep.getEndpointHost();
			Integer port = ep.getEndpointPort();
			return remoteNo.equals(no) && this.remoteHost.equals(host) && this.remotePort.equals(port);
		} else {
			return false;
		}
	}

	@Override
	public int hashCode() { 
		
		if (hashCode == 0) {
			
			hashCode = 17;
			hashCode = 37 * hashCode + remoteNo.hashCode();
			hashCode = 37 * hashCode + remoteHost.hashCode();
			hashCode = 37 * hashCode + remotePort.hashCode();
		}
		return hashCode;
	}
	
	@Override
	public String toString() {
		
		StringBuilder sb = new StringBuilder();
		sb.append("ProxyEndpoint[");
		sb.append("remoteNo:").append(remoteNo).append(", ");
		sb.append("remoteHost:").append(remoteHost).append(", ");
		sb.append("remotePort:").append(remotePort);
		sb.append("]");
		return sb.toString();
	}

	public EndpointChangeListner getListner() {

		throw new UnsupportedOperationException();
	}

	public void setListner(EndpointChangeListner listner) {
		
		throw new UnsupportedOperationException();
	}
	
	/**
	 * 返回Remote rpc代理
	 * @return Endpoint rpc代理
	 */
	private Endpoint getRemote() {
		
		if (null == remote) {
			InetSocketAddress remoteAddress = new InetSocketAddress(remoteHost, remotePort);
			rpcService = RPCFactory.getEndpoint(remoteAddress);
			remote = rpcService.importInstance(Endpoint.class); 
			remoteNo = remote.getEndpointNo();
			log.debug("创建一个代理端点[{}]", this);
		}
		return remote;
	}
}
